﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using FlagLib.IO;
using TagLib;

namespace FlagTunes.Core
{
    public class SongFinder
    {
        private readonly DirectoryScanner scanner;
        private readonly List<string> supportedExtensions = new List<string>(new[] { ".mp3", ".wav" });
        private readonly List<Song> songsFound;

        /// <summary>
        /// Gets the supported extension.
        /// </summary>
        /// <value>The supported extension.</value>
        public IEnumerable<string> SupportedExtensions
        {
            get { return this.supportedExtensions; }
        }

        /// <summary>
        /// Gets the songs found.
        /// </summary>
        /// <value>The songs found.</value>
        public IEnumerable<Song> SongsFound
        {
            get { return this.songsFound.AsReadOnly(); }
        }

        /// <summary>
        /// Occurs when a song has been found.
        /// </summary>
        public event EventHandler<SongEventArgs> SongFound;

        /// <summary>
        /// Occurs when the song crawler has finished.
        /// </summary>
        public event EventHandler Finished;

        /// <summary>
        /// Initializes a new instance of the <see cref="SongFinder"/> class.
        /// </summary>
        /// <param name="path">The path.</param>
        public SongFinder(string path)
        {
            this.songsFound = new List<Song>();
            this.scanner = new DirectoryScanner(path);
            this.scanner.FileFound += scanner_FileFound;
        }

        /// <summary>
        /// Starts the song crawler.
        /// </summary>
        public void Start()
        {
            this.scanner.Start();

            this.OnFinished(EventArgs.Empty);
        }

        /// <summary>
        /// Starts the song crawler asynchronous.
        /// </summary>
        public void StartAsync()
        {
            ThreadPool.QueueUserWorkItem(callback => this.Start());
        }

        /// <summary>
        /// Raises the <see cref="SongFound"/> event.
        /// </summary>
        /// <param name="e">The <see cref="FlagTunes.Core.SongEventArgs"/> instance containing the event data.</param>
        protected virtual void OnSongFound(SongEventArgs e)
        {
            if (this.SongFound != null)
            {
                this.SongFound(this, e);
            }
        }

        /// <summary>
        /// Raises the <see cref="Finished"/> event.
        /// </summary>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        protected virtual void OnFinished(EventArgs e)
        {
            if (this.Finished != null)
            {
                this.Finished(this, e);
            }
        }

        /// <summary>
        /// Handles the FileFound event of the directory scanner.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="FlagLib.IO.FileEventArgs"/> instance containing the event data.</param>
        private void scanner_FileFound(object sender, FileEventArgs e)
        {
            if (this.SupportedExtensions.Contains(e.File.Extension))
            {
                try
                {
                    Tag tag = null;

                    switch (e.File.Extension)
                    {
                        case ".mp3":
                            using (var file = new TagLib.Mpeg.AudioFile(e.File.FullName))
                            {
                                tag = file.Tag;
                            }
                            break;

                        case ".wav":
                            using (var file = new TagLib.WavPack.File(e.File.FullName))
                            {
                                tag = file.Tag;
                            }
                            break;
                    }

                    if (tag != null)
                    {
                        var song = new Song(e.File.FullName, DateTime.Now)
                                       {
                                           Album = tag.Album ?? String.Empty,
                                           Artist = tag.FirstPerformer ?? "Unknown Artist",
                                           Genre = tag.FirstGenre ?? String.Empty,
                                           Title = tag.Title ?? String.Empty
                                       };

                        this.songsFound.Add(song);
                        this.OnSongFound(new SongEventArgs(song));
                    }
                }

                catch (CorruptFileException)
                {
                }
            }
        }
    }
}